(ns user.menuClient
	(:import (javax.swing JFrame JPanel JButton JLabel table.DefaultTableModel JToolBar JTable JScrollPane JMenuBar JMenu JMenuItem JComboBox
		 table.DefaultTableModel JTextField SpringLayout KeyStroke event.TableModelListener event.TableModelEvent table.AbstractTableModel 
		 table.TableRowSorter ImageIcon JOptionPane)
		 (java.io PrintWriter File FileInputStream FileOutputStream)
        (java.awt.event ActionListener ActionEvent KeyEvent)
        (java.awt BorderLayout Dimension Container FlowLayout GridLayout)
    	(java.net Socket)
    	(java.util Scanner))
    (:use server.dbmain user.commonFunctions user.newMenu)
    (:use clojure.contrib.gen-html-docs)
)

(defn client-reload
	"Runs the protocol to reload the database from the server"
	[data model dbname host port]
	(let [socket (Socket. host port)]
		(with-open [
			input (.getInputStream socket)
			output (PrintWriter. (.getOutputStream socket))
			output-stream  (FileOutputStream. dbname)
			]
			(let [buffer (byte-array 1024)]
				(.println output "give-me-the-database")
				(.flush output)
				(loop [len (.read input buffer)]
					(if (> len 0)
						(do
							(.write output-stream buffer, 0, len)
							(recur (.read input buffer))
						)
					)
				)
			)
		)
	)
)

;;------------------------------------------------------------------------------------------------------------------------------------

(defn client-add
		[data model dbname host port]
		(let [socket (Socket. host port)]
				(with-open [
					input (.getInputStream socket)
					output (PrintWriter. (.getOutputStream socket))
					output-stream  (FileOutputStream. dbname)
					]
					(let [buffer (byte-array 1024)]
						(.println output "create-new-record")
						(.flush output)
					)
		))
)

;;------------------------------------------------------------------------------------------------------------------------------------

(defn client-delete
	"Runs the protocol to erase a record from the database"
	[dbname data rec-no model number-in-table host port]
	(client-reload data model dbname host port) ;;reload the db
	(filter-db data model dbname) ;;update the interface
	(let [socket (Socket. host port)
		rec-num (row-for-rec rec-no model)]
		(with-open [
			input (Scanner. (.getInputStream socket))
			output (PrintWriter. (.getOutputStream socket))
			output-stream  (FileOutputStream. dbname)
			]
			(if (not= rec-num (- 1))
				;; if the record-exists
				(do
					(.println output "delete-record")
					(.println output rec-no)
					;;(if (= "ok" (.next Input)))
				)
				;; if it had already been deleted
				;;do nothing
			)
		)
		(client-reload data model dbname host port) ;;reload the db
		(filter-db data model dbname) ;;update the interface
	)
)

(defn update-record-client
	[dbname rec-no new-data data model dbname host port frame]
	"Runs the protocol to update a record in the database"
	(client-reload data model dbname host port) ;;reload the db
	(filter-db data model dbname) ;;update the interface
	(let [socket (Socket. host port)
		rec-num (row-for-rec rec-no model)]
		(with-open [
			input (Scanner. (.getInputStream socket))
			output (PrintWriter. (.getOutputStream socket))
			output-stream  (FileOutputStream. dbname)
			]
			(if (= rec-num (- 1))
				;; if it had already been deleted
				;; tell the user
				(do
					(JOptionPane/showMessageDialog 
						frame
						"The record had already been deleted.",
						"Out of date error",
					JOptionPane/ERROR_MESSAGE)
				)
				;; if it still exists, update
				(dosync
					(.println output "update-record")
					(.println output rec-no)
					
					(.println output (:name new-data))
					(.println output (:location new-data))
					(.println output (:rate new-data))
					(.println output (:owner new-data))
					(.println output (:date new-data))
					(.println output (:size new-data))
					(.println output (:smoking new-data))
					(.flush output)
				)
			)
		)
		(client-reload data model dbname host port) ;;reload the db
		(filter-db data model dbname) ;;update the interface
	)
)

(defn new-menu-client
	"Displays the main menu"
	[dbname host port]
	(print dbname)
	(let [
		data 				{:name (str) :location (str) :rate (str) 
    	  	  				 :date (str) :size (str) :smoking (str) :owner (str)}
		frame   			(JFrame. "Main Menu")
		content-pane		(.getContentPane frame)
    	panel-table			(JPanel. )
    	panel-menu			(JPanel. )
    	model   			(table-model)
    	table   			(JTable. model)
    	scrollPane 			(JScrollPane. table)
    	return-list			(find-in-db data dbname)
    	dictionary			(map #(read-record dbname %) return-list)
    	margin 				5
    	fields-combo-box 	(JComboBox. (into-array ["Name" "Location" "Size"
    							"Smoking" "Rate" "Date" "Owner"]))
        find-text-field		(JTextField. 15)
        sorter				(TableRowSorter. model)
    	
    	create-handler (proxy [ActionListener] []
        (actionPerformed [event]
        		(client-add data model dbname host port)
        		(client-reload data model dbname host port)
        		(filter-db data model dbname)

   	     ))
        find-handler (proxy [ActionListener] []
        (actionPerformed [event]
        		(client-reload data model dbname host port)
        		(filter-db data model dbname)
        	(let [
        		selected (.getSelectedIndex fields-combo-box)
        		find-field (if (not (empty? (.trim (.getText find-text-field)))) 
        				(upperLetter (.getText find-text-field)) (.getText find-text-field))
        		]
        		(if (= selected 0) (filter-table (assoc data :name 	 	find-field) model dbname))
        		(if (= selected 1) (filter-table (assoc data :location  find-field) model dbname))
        		(if (= selected 2) (filter-table (assoc data :size 	 	find-field) model dbname))
        		(if (= selected 3) (filter-table (assoc data :smoking  	find-field) model dbname))
        		(if (= selected 4) (filter-table (assoc data :rate 	 	find-field) model dbname))
        		(if (= selected 5) (filter-table (assoc data :date 	 	find-field) model dbname))
        		(if (= selected 6) (filter-table (assoc data :owner 	find-field) model dbname))
        	)
        ))
    	delete-handler (proxy [ActionListener] []
          	  (actionPerformed [event]
          	  	  
          	  	  (loop [n 0]
          	  	  	  (if (< n (.getRowCount table))
          	  	  	  	  (if (.isRowSelected table n)
          	  	  	  	  	  ;though we can't see the recNo in the table, the model keeps that data
          	  	  	  	  	  (do
          	  	  	  	  	  	  (client-delete dbname data (.getValueAt model n 7) model n host port)
          	  	  	  	  	  	  
          	  	  	  	  	  )
          	  	  	  	  	  (recur (inc n))
          	  	  	  	  )
          	  	  	  )
          	  	  )
          	  	  
        ))
        update-handler (proxy [TableModelListener] []
          	  (tableChanged [event]
          	  	  (if (= TableModelEvent/UPDATE (.getType event))
					  (let [
						  row 	(.getFirstRow event)
						  nme  	(upperLetter (.getValueAt table row 0))
						  loc   (upperLetter (.getValueAt table row 1))
						  sze 	(.getValueAt table row 2)
						  smk 	(.getValueAt table row 3)
						  frate	(.getValueAt table row 4)
						  date 	(.getValueAt table row 5)
						  own 	(upperLetter (.getValueAt table row 6))
						  ]
						  
						  (update-record-client
							  dbname 
							  (.getValueAt model row 7)
							  {:name nme :location loc :rate frate :owner (str own)
							  :date date :size (str sze) :smoking (if smk "Y" "N")}
						  	  data model dbname host port frame
						  )
						  
						  
					  )
				  )
        ))
        exit-handler (proxy [ActionListener] []
          	(actionPerformed [event]
          	(.setVisible frame false)
          	(.delete dbname)
          	(.dispose frame)
        ))
        reload-handler (proxy [ActionListener] []
          	(actionPerformed [event]
          	(client-reload data model dbname host port)
          	(filter-db data model dbname)
        ))]
        
        
        (.setRowSorter table sorter)
        (.setDefaultCloseOperation frame JFrame/DISPOSE_ON_CLOSE)
		(.setPreferredSize frame (Dimension. 600 300))
		(.setLayout frame (BorderLayout.))
		(.setLayout content-pane (BorderLayout.))
		(.setLayout panel-menu (BorderLayout.))
		
		(.add panel-menu 
			(create-menu-bar create-handler find-handler delete-handler exit-handler reload-handler)
				BorderLayout/NORTH)
		(.add panel-menu 
			(create-tool-bar create-handler find-handler delete-handler fields-combo-box find-text-field reload-handler)
				BorderLayout/SOUTH)
				
		(.add content-pane panel-menu  BorderLayout/NORTH)
		
		(doto model
			(.addColumn "Name")
			(.addColumn "Location")
			(.addColumn "Size")
			(.addColumn "Smoking")
			(.addColumn "Rate")
			(.addColumn "Date")
			(.addColumn "Owner")
			(.addColumn "RecNo") 
		)
		
		(.setAutoResizeMode table JTable/AUTO_RESIZE_SUBSEQUENT_COLUMNS)
		(.setFillsViewportHeight table true)
		
		(.add content-pane scrollPane BorderLayout/CENTER)
		(.pack frame)
		(.setLocationRelativeTo frame nil)
		(.setVisible frame true)
		(dorun (map #(addRow-table %1 %2 model) return-list dictionary))
		
		(.setPreferredWidth (.getColumn (.getColumnModel table) 0) (+ 200 (* 2 margin))) ;name
		(.setPreferredWidth (.getColumn (.getColumnModel table) 1) (+ 150 (* 2 margin))) ;locatio
		(.setPreferredWidth (.getColumn (.getColumnModel table) 2) (+ 50 (* 2 margin)))  ;size
		(.setPreferredWidth (.getColumn (.getColumnModel table) 3) (+ 80 (* 2 margin)))	 ;smoking
		(.setPreferredWidth (.getColumn (.getColumnModel table) 4) (+ 100 (* 2 margin))) ;rate
		(.setPreferredWidth (.getColumn (.getColumnModel table) 5) (+ 100 (* 2 margin))) ;date
		(.setPreferredWidth (.getColumn (.getColumnModel table) 6) (+ 100 (* 2 margin))) ;owner
		
		(.addTableModelListener model update-handler)
		(.removeColumn table (.getColumn table "RecNo"))
	frame)
)

;;------------------------------------------------------------------------------------------------------------------------------------	

;(new-menu "db-1x2.db")
(generate-documentation-to-file "./user/documentation.html" ['user.newMenu 'user.commonFunctions 'server.readbinfile 'server.dbmain 'server.servidor 'user.cliente 'start])
